// http://code.google.com/chrome/extensions/options.html

var enum = {
	visibleTo: {
		everybody: 1,
		friends: 2,
		family: 3,
		friendsOrFamily: 4,
		nobody: 5
	}
};

var ti = {
	formatDate: function(d) {
		// eg. 2010-10-16 09:25:48
		d = d.substring(0, d.lastIndexOf(' '));
		var part = d.split('-');
		var month = ['January','February','March','April','May','June','July','August','September','October','November','December'];
		return month[(part[1] * 1) - 1] + ' ' + (part[2] * 1) + ', ' + part[0];
	},
	alert: function(message, title) { window.alert(title + ': ' + message); },
	formatText: function(text) { return text; }
}

// http://www.flickr.com/services/api/response.json.html
var flickr = {
	api: 'http://api.flickr.com/services/rest/?format=json&nojsoncallback=1',
	key: '459e62a3f2bcd299cd8fe8a58b8d1fb6',
	salt: '135678bbdb34a901',
	token: '72157626274031078-5cded0ba3b017eba',
	permission: 'read',
	debugApiCall: false,
	callName: 'jsoncallback',
	visibleTo: 0,
	page: 'http://flickr.com/photo.gne?id=',
	xhr: null,
	get: {
		sizes: 'flickr.photos.getSizes',
		location: 'flickr.photos.geo.getLocation',
		exif: 'flickr.photos.getExif',
		frob: 'flickr.auth.getFrob',
		token: 'flickr.auth.getToken',
		photo: 'flickr.photos.getInfo',
		collection: 'flickr.collections.getTree',
		setPhotos: 'flickr.photosets.getPhotos',
		setInfo: 'flickr.photosets.getInfo',
		setList: 'flickr.photosets.getList',
		sizes: 'flickr.photos.getSizes'
	},
	url: function(methodName, id) {
		// generate API URL
		// http://www.flickr.com/services/api/
		if (methodName) {
			var link = this.api
				+ '&api_key=' + this.key
				+ '&method=' + methodName;
			if (id) {
				if (/\.photos\./.test(methodName)) { link += '&photo_id=' + id; }
				else if (/\.collections\./.test(methodName)) { link += '&collection_id=' + id; }
				else if (/\.photosets\./.test(methodName)) {
					link += '&photoset_id=' + id;
					if (this.visibleTo) { link += '&privacy_filter=' + this.visibleTo; }
				}
				else if (/getToken/.test(methodName)) { link += '&frob=' + id; }
			}
			return this.sign(link, this.getJsonpCallback(methodName, id));
		} else {
			return this.page + id;
		}
	},
	cancel: function() { if (this.xhr) { this.xhr.abort(); } },
	service: function(id, methodName, callback, jsonFn) {
		if (!this.token && methodName != this.get.frob) {
			// user needs to authenticate to get a token
			this.service(null, this.get.frob, function(r) {
				if (flickr.goodResponse(r, flickr.get.frob)) {
					flickr.login(r.frob._content);
				} else {
					callback({ stat: 'fail', code: r.code, message: 'Unable to authenticate at Flickr' });
				}
			});
		} else {
			// make an authenticated call
			var url = this.url(methodName, id);
			var xhr = new XMLHttpRequest();
			xhr.onreadystatechange = function() {
				if (xhr.readyState == 4) {
					var r = new responseObject(xhr, url);
					if (xhr.status == 200) {
						try {
							r.json = JSON.parse(xhr.responseText);
							if (jsonFn) { r.json = jsonFn(r.json); }
						} catch (e) {
							r.status.success = false;
							r.status.message = e.description || e.message;
						}
					} else {
						r.status.success = false;
						r.status.message = r.status.message || 'invalid HTML response';
					}
					callback(r);
				}
			}
			console.log('loading ' + url);
			xhr.open('GET', url, true);
			xhr.send();
		}
	},
	parseExif: function(data) {
		if (!data || !data.length) { return null; }
		var allow = /(IFD0|ExifIFD|XMP-tiff|XMP-aux)/;
		var exif = new Object();
		for (var i = 0; i < data.length; i++) {
			if (allow.test(data[i].tagspace)) {
				exif[data[i].label] = data[i].raw._content;
			}
		}
		return exif;
	},
	getJsonpCallback: function(methodName, id) {
		if (!this.customCallback) {
			// non-custom callback persists for only a single call
			// used to create debug API links
			this.customCallback = true;
			return null;
		}
		var name = methodName.substr(methodName.lastIndexOf('.') + 1);
		if (id) { name += id.replace(/\W/, ''); }
		return name;
	},
	sign: function(url, jsonpCallback) {
		// http://www.flickr.com/services/api/auth.spec.html
		if (this.token) { url += '&auth_token=' + this.token; }
		var re = /[\?&]([^&=\?]+=[^&=]+)/g;
		// MD5 needs to include the callback parameter that is automatically
		// added by jQuery
		var params = (jsonpCallback) ? [this.callName + '=' + jsonpCallback] : [];
		var match;
		while (match = re.exec(url)) { params.push(match[1]); }
		params.sort();
		url += '&api_sig=' + hex_md5(this.salt + params.toString().replace(/[=,]/g, ''));
		if (this.debugApiCall) {
			ti.alert('<a href="' + url + '&' + this.callName + '=' + jsonpCallback
				+ '" target="_new">Manually Repeat API Call</a>');
		}
		return url;
	},
	getCollection: function(id, callback) {
		if (/\D/.test(id)) { id = ti.database + '-' + id; }
		flickr.service(id, flickr.get.collection, function(r) {
			callback(new collectionObject(r.collections.collection[0]));
		});
	},
	getSetList: function(callback) {
		flickr.service(null, flickr.get.setList, callback, function(json) {
			var list = [];
			for (var i = 0; i < json.photosets.photoset.length; i++) {
				if (json.photosets.photoset[i].photos) {
					list.push(new setObject(null, json.photosets.photoset[i]));
				}
			}
			return list;
		});
	},
	getSet: function(id, callback) {
		if (/\D/.test(id)) {
			// match non-numeric name to ID
			if (ti.sets[id]) {
				// use cached set ID
				flickr.getSet(ti.sets[id].id, callback);
			} else {
				// load collection to find set ID
				flickr.getCollection(ti.collection, function(c) {
					var match = c.findSet(id);
					if (match) {
						flickr.getSet(match, callback);
					} else {
						ti.alert('Unable to find set ' + id);
					}
				});
			}
		} else {
			flickr.service(id, flickr.get.setPhotos, function(r) {
				var photos = r.photoset;
				flickr.service(id, flickr.get.setInfo, function(r) {
					callback(new setObject(photos, r.photoset));
				});
			});
		}
	},
	login: function(frob) {
		// generate Flickr login links for debugging
		this.customCallback = false;
		var message = '<strong>Configuration Required</strong>';
		var url = 'http://flickr.com/services/auth/'
			+ '?api_key=' + this.key
			+ '&perms=' + this.permission
			+ '&frob=' + frob
		message += '<ol><li><a href="' + this.sign(url) + '" target="_new">authenticate</a></li>'
		url = this.url(this.get.token, frob);
		message += '<li><a href="' + url + '" target="_new">retrieve token</a></li></ol>';
		ti.alert(message);
	}
};

function responseObject(xhr, url) {
	this.status = {
		'success': true,
		'message': xhr.statusText,
		'code': xhr.status
	},
	this.url = url;
	this.json =  null;
}

function collectionObject(tree) {
	// object representing a Flickr collection
	var _c = this;
	this.id = tree.id;
	this.title = ti.formatText(tree.title);
	this.collections = [];
	this.sets = [];
	this.findSet = function(url) {
		// search recursively for the set with the url created by setInfoObject.url()
		for (var i in _c.sets) {
			if (_c.sets[i].url() == url) { return _c.sets[i].id; }
		}
		for (var i in _c.collections) {
			var id = _c.collections[i].findSet(url);
			if (id) { return id; }
		}
		return null;
	}
	parseCollections();
	parseSets();

	function parseCollections() {
		for (var i in tree.collection) {
			_c.collections.push(new collectionObject(tree.collection[i]));
		}
	}
	
	function parseSets() {
		for (var i in tree.set) { _c.sets.push(new setInfoObject(tree.set[i])); }
	}
	
	function setInfoObject(info) {
		var _s = this;
		this.id = info.id;
		this.title = ti.formatText(info.title);
		this.description = ti.formatText(info.description);
		this.url = function() {
			// convert the title to URL friendly text
			return _s.title
				.replace(/\W/g, '-')
				.replace(/\-{2,}/, '-')
				.replace(/\-$/, '')
				.toLowerCase();
		}
		this.link = function() {
			return '<a href="/' + _s.url() + '">' + _s.title + '</a>';
		}
	}
}


// http://www.flickr.com/services/api/flickr.photosets.getInfo.html
// http://www.flickr.com/services/api/flickr.photosets.getPhotos.html
function setObject(set, info) {
	// object representing a Flickr set
	var _s = this;
	this.id = info.id;
	var _keepLoading = true;
	var _timer = null;
	var _complete = false;
	this.loadDelay = 2000;	// delay between image preload requests
	this.title = ti.formatText(info.title._content);
	this.description = ti.formatText(info.description._content);
	this.total = info.photos;
	this.photos = [];
	this.coverPhoto = null;
	
	if (set) { parsePhotos(); }

	function parsePhotos() {
		_s.total = set.total;
		for (var i = 0; i < set.photo.length; i++) {
			var p = new photoObject(set.photo[i], _sizeFor);
			_s.photos.push(p);
			if (set.photo[i].isprimary) { _s.coverPhoto = p; }
		}
	}
	function photoObject(api, sizeFor) {
		// object representing a Flickr photo in a set
		var _p = this;
		var _id = api.id;
		var _imageSize = [
			{ url: '', width: 0, height: 0 },
			{ url: '', width: 0, height: 0 }
		];
		this.image = new Image();
		this.title = null;
		this.description = null;
		this.pageUrl = null;
		this.mapUrl = null;
		this.thumbnail = null;
		this.dateTaken = null;
		this.hidden = false;
		this.loaded = false;
		
		this.setSizeFor = function(sizeFor) {
			if (_sizeFor != sizeFor) {
				_sizeFor = sizeFor;
				if (_p.loaded) { setupImage(); }
			}
		}
		
		this.load = function(callback) {
			// load details from Flickr
			flickr.service(_id, flickr.get.photo, function(r) {
				var p = r.photo;
				_p.title = ti.formatText(p.title._content);
				_p.description = ti.formatText(p.description._content);
				_p.pageUrl = p.urls.url[0]._content;
				_p.dateTaken = ti.formatDate(p.dates.taken);
				
				if (p.location && p.location.latitude && p.location.longitude) {
					_p.mapUrl = 'http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q='
						+ p.location.latitude + ',' + p.location.longitude + '&t=h&z=15';
				}
				flickr.service(_id, flickr.get.sizes, function(r) {
					// find the largest size that will fit
					for (var i = r.sizes.size.length - 1; i >= 0; i--) {
						// record maximum size for both screen and window
						var size = r.sizes.size[i];
						if (checkSize(size, _s.screenWidth, enum.sizeFor.screen)
						 && checkSize(size, _s.windowWidth, enum.sizeFor.window)) { break; }
					}
					setupImage();
					_p.loaded = true;
					callback();
				});
			});
		}
		
		function setupImage() {
			var s = _imageSize[_sizeFor];
			
			// setting image object source triggers download to browser cache
			_p.image.src = s.url;
			_p.image.height = s.height;
			_p.image.width = s.width;
		}
		
		function checkSize(size, width, sizeEnum) {
			var s = _imageSize[sizeEnum];
			if (s.width != 0) {
				return true;
			} else if ((size.width * 1) + _s.gutterWidth <= width) {
				//ti.alert(sizeEnum + ' ' + size.width);
				s.url = size.source
				s.width = size.width * 1;
				s.height = size.height * 1;
				return true;
			} else {
				return false;
			}
		}
	}
}